#ifndef __VECTOR3D_H__
#define __VECTOR3D_H__

#include <math.h>
#include <stdio.h>

template <class T>
class vector3d
{
public:
	T X;
	T Y;
	T Z;

public:
	vector3d() : X(0), Y(0), Z(0) {}
	vector3d(T nx, T ny, T nz) : X(nx), Y(ny), Z(nz) {}
	vector3d(T *nv) : X(*nv), Y(*(nv+1)), Z(*(nv+2)) {}
	vector3d(const vector3d<T>& other) : X(other.X), Y(other.Y), Z(other.Z) {}

	void Set(const vector3d<T>& other)  {  X = other.X;Y = other.Y;Z = other.Z; }
	void Set(T nx,T ny,T nz)  {  X = nx;Y = ny;Z = nz; }
	vector3d<T> operator-() const { return vector3d<T>(-X, -Y, -Z); }
	vector3d<T>& operator=(const vector3d<T>& other) { X = other.X; Y = other.Y; Z = other.Z; return *this; }
	vector3d<T> operator+(const vector3d<T>& other) const { return vector3d<T>(X + other.X, Y + other.Y, Z + other.Z); }
	vector3d<T>& operator+=(const vector3d<T>& other) { X+=other.X; Y+=other.Y; Z+=other.Z; return *this; }
	vector3d<T> operator+(const T val) const { return vector3d<T>(X + val, Y + val, Z + val); }
	vector3d<T>& operator+=(const T val) { X+=val; Y+=val; Z+=val; return *this; }
	vector3d<T> operator-(const vector3d<T>& other) const { return vector3d<T>(X - other.X, Y - other.Y, Z - other.Z); }
	vector3d<T>& operator-=(const vector3d<T>& other) { X-=other.X; Y-=other.Y; Z-=other.Z; return *this; }
	vector3d<T> operator-(const T val) const { return vector3d<T>(X - val, Y - val, Z - val); }
	vector3d<T>& operator-=(const T val) { X-=val; Y-=val; Z-=val; return *this; }
	vector3d<T> operator*(const vector3d<T>& other) const { return vector3d<T>(X * other.X, Y * other.Y, Z * other.Z); }
	vector3d<T>& operator*=(const vector3d<T>& other) { X*=other.X; Y*=other.Y; Z*=other.Z; return *this; }
	vector3d<T> operator*(const T v) const { return vector3d<T>(X * v, Y * v, Z * v); }
	vector3d<T>& operator*=(const T v) { X*=v; Y*=v; Z*=v; return *this; }

	vector3d<T> operator/(const vector3d<T>& other) const { return vector3d<T>(X / other.X, Y / other.Y, Z / other.Z); }
	vector3d<T>& operator/=(const vector3d<T>& other) { X/=other.X; Y/=other.Y; Z/=other.Z; return *this; }
	vector3d<T> operator/(const T v) const { T i=(T)1.0/v; return vector3d<T>(X * i, Y * i, Z * i); }
	vector3d<T>& operator/=(const T v) { T i=(T)1.0/v; X*=i; Y*=i; Z*=i; return *this; }

	bool operator<=(const vector3d<T>&other) const { return X<=other.X && Y<=other.Y && Z<=other.Z;}
	bool operator>=(const vector3d<T>&other) const { return X>=other.X && Y>=other.Y && Z>=other.Z;}
	bool operator<(const vector3d<T>&other) const { return X<other.X && Y<other.Y && Z<other.Z;}
	bool operator>(const vector3d<T>&other) const { return X>other.X && Y>other.Y && Z>other.Z;}
	bool operator==(const vector3d<T>& other) const { return X==other.X && Y==other.Y && Z==other.Z;}
	bool operator!=(const vector3d<T>& other) const { return X!=other.X || Y!=other.Y || Z!=other.Z;}
	bool operator==(const T& other) const { return X==other && Y==other && Z==other;}
	bool operator!=(const T& other) const { return X!=other || Y!=other || Z!=other;}

	T GetModul() const
	{
		return sqrt(X*X + Y*Y + Z*Z);
	}

	T GetDist(vector3d<T> &other) const
	{
		vector3d<T> Dist(other.X - X,other.Y - Y,other.Z - Z);
		return Dist.GetModul();
	}

	inline void Normalize()
	{
		vPos r;

		r = sqrt(X*X + Y*Y + Z*Z);
		if (r == 0.0) return;

		X /= r;
		Y /= r;
		Z /= r;
	}

	inline vector3d<T> ProductoCruz(vector3d<T> &w)
	{
		return vector3d<T>(Y*w.Z - w.Y*Z,Z*w.X - w.Z*X,X*w.Y - w.X*Y);
	}

	inline void ProductoCruz(vector3d<T> &v,vector3d<T> &w)
	{
		X = v.Y*w.Z - w.Y*v.Z;
		Y = v.Z*w.X - w.Z*v.X;
		Z = v.X*w.Y - w.X*v.Y;
	}

	std::string GetStr() const
	{
		char Cad[100];
		sprintf(Cad,"(%f,%f,%f)",X,Y,Z);
		return Cad;
	}
};

typedef vector3d<vPos> vector3dvpos;
typedef vector3d<f32> vector3df32;
typedef vector3d<u32> vector3du32;
typedef vector3d<s32> vector3ds32;
typedef vector3d<u16> vector3du16;
typedef vector3d<s16> vector3ds16;
typedef vector3d<u8> vector3du8;
typedef vector3d<s8> vector3ds8;

#endif
